﻿using MQTTnet;
using MQTTnet.Core;
using MQTTnet.Core.Client;
using MQTTnet.Core.Protocol;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace UDPServer
{
    public partial class FrmServer : Form
    {
        public static int resultNoConnect = -1; //没有连接错误
        public static int resultTimeOut = -2;   //通讯超时错误
        public static int resultFileError = -3; //文件上传下载错误(嵌入式内部问题)
        public static int resultFun = -5;
        public static int MaxConnectTimes = 10; //重试次数
        #region 通讯相关变量 

        public string msg1 = "";
        public string msg2 = "";

        SystemParam sysParam = SystemParam.Create();
        DateTime m_dtLastUdpMsgTime = DateTime.Now;
        StringBuilder m_strBuilderUdp = new StringBuilder();
         

        NetworkStream m_tcpStream;   //tcp数据流  
        TcpClient m_tcpClient = null;
        bool m_threadTcpRun = true;

        #endregion





        #region 命令相关变量

        Mutex m_mut = new Mutex();   //保存文件的互斥体
        bool m_bWorking = false;     //是否正在执行任务 　
        string m_strStateMsg = "";
        int iTimes = 0;
        bool m_bLoading = true;

        MqttClient mqttClient = null; 
        Hashtable m_hashIpList = new Hashtable(); 
        string m_strMqttMsg = "";  

        public static FrmServer myself = null;

        #endregion
        public FrmServer()
        {
            InitializeComponent();
            IsConnected = false;
            IsMqttConnected = false;
            myself = this;

            tbLocalIP.Text = sysParam.tcpIP;
            tbTcpPort.Text = sysParam.tcpPort.ToString();
            tbStateMsg.Text = sysParam.tcpCmd;
            cbAutoSendTcp.Checked = sysParam.bTcpAutoSend ;

            tbMqttIp.Text = sysParam.mqttIp;
            tbMqttPort.Text = sysParam.mqttPort.ToString();
            tbMqttUsr.Text = sysParam.mqttUsr;
            tbMqttPwd.Text = sysParam.mqttPwd;
            tbMqttTopic.Text = sysParam.mqttPath;
            tbMqttContent.Text = sysParam.mqttContent; 
            nudMqttInteval.Value = sysParam.iMqttInteval;
            devicename.Text = sysParam.mqttDevName;

            cbMqttAutoConn.Checked = sysParam.bMqttAutoConn;
            cbAllowSim.Checked = sysParam.bSimulateData;
            cbMqttAutoSend.Checked = sysParam.bMqttAutoSend;

            try
            {
                Computer mycomputer = new Computer();
                sysParam.cpuID = mycomputer.CpuID; 
                timer1.Start();
                StartIPC(); 
            }
            catch (Exception)
            { 
            }

            
        }
        

        #region 继承的接口

     
        /// <summary>
        /// 判断是否连接
        /// </summary>
        public bool IsConnected
        {
            get;
            set;
        }
        public bool IsTcpConnecting
        {
            get;
            set;
        }
        public bool IsMqttConnected
        {
            get;
            set;
        }
        public bool IsMqttConnecting
        {
            get;
            set;
        }


        #endregion

        #region Tcp函数


        private void StartIPC()
        { 
            Thread IPCThread = new Thread(Listening);
            IPCThread.Name = "QYMotionTcpServerIPCThread";
            IPCThread.IsBackground = true;
            IPCThread.Start();
        }
        public int ConnectToTcpServer()
        {
            IsTcpConnecting = true;
            int iResult = -1; 
            try
            { 
                m_tcpClient = new TcpClient(sysParam.tcpIP, sysParam.tcpPort);
                if (m_tcpClient.Connected)
                {
                    IsConnected = true; 
                    m_tcpStream = m_tcpClient.GetStream();
                    iResult = 0;
                }
            }
            catch (Exception ioe)
            {
                Console.WriteLine("Exception: {0}", ioe);
            }
            IsTcpConnecting = false;
            return iResult;
        }
        /// <summary>
        /// 监听线程
        /// </summary>
        private void Listening()
        {
            // Buffer for reading data
            Byte[] bytes = new Byte[512];

            // Enter the listening loop.
            while (m_threadTcpRun)
            {
                if (m_tcpClient == null || !m_tcpClient.Connected)
                {
                    IsConnected = false;
                    Thread.Sleep(1000);
                    Application.DoEvents();
                    continue;
                }
                else
                {
                    int i;
                    try
                    {
                        IsConnected = true;
                        while ((i = m_tcpStream.Read(bytes, 0, bytes.Length)) != 0)
                        {
                            IsConnected = true;
                            String data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);

                            //0.输出收到的消息
                            byte[] cmdData = bytes.Take(i).ToArray();
                            string msg = Encoding.ASCII.GetString(cmdData) ; 
                            if(msg.StartsWith(sysParam.tcpCmd) )
                            { 
                                m_strStateMsg = msg.Substring(sysParam.tcpCmd.Length + 1);
                            }

                            m_bWorking = false;
                        }
                    }
                    catch 
                    {
                        IsConnected = false;
                        m_tcpStream.Close();
                        m_tcpClient.Close();
                        m_tcpClient = null;
                        m_tcpStream = null;  
                    }
                }
                int iTime = (int)(2 * 1000);
                Thread.Sleep(iTime);
                Application.DoEvents();
            }
        }
 
         
        /// <summary>
        /// 发送命令
        /// </summary>
        /// <param name="qyCmd"></param>
        /// <returns></returns>
        public int SendCmd(string qyCmd)
        {
            if (!IsConnected) return resultNoConnect;
            if (m_tcpStream == null) return resultNoConnect;

            m_mut.WaitOne();
            
            byte[] cmd = Encoding.ASCII.GetBytes(qyCmd); 
            lock (m_tcpStream)
            {
                m_tcpStream.Write(cmd, 0, cmd.Length);
            }
            m_mut.ReleaseMutex();
            return 0;
        }

        #endregion

        #region  MQTT函数

        /// <summary>
        /// 连接服务器
        /// </summary>
        /// <returns></returns>
        private async Task ConnectMqttServerAsync()
        {
            IsMqttConnecting = true;
            if (mqttClient == null)
            {
                mqttClient = new MqttClientFactory().CreateMqttClient() as MqttClient;
                mqttClient.ApplicationMessageReceived += MqttClient_ApplicationMessageReceived;
                mqttClient.Connected += MqttClient_Connected;
                mqttClient.Disconnected += MqttClient_Disconnected; 
            }

            try
            {
                var options = new MqttClientTcpOptions
                {
                    Server = sysParam.mqttIp,
                    Port = sysParam.mqttPort,
                    ClientId = Guid.NewGuid().ToString().Substring(0, 5),
                    UserName = sysParam.mqttUsr,
                    Password = sysParam.mqttPwd,
                    CleanSession = true
                }; 
                await mqttClient.ConnectAsync(options); 
            }
            catch (Exception ex)
            {               

                Invoke((new Action(() =>
                {
                    lbMqttMsg.Text = ($"连接到MQTT服务器失败！" + Environment.NewLine + ex.Message + Environment.NewLine);
                })));
            }
            IsMqttConnecting = false;
        }
        /// <summary>
        /// 服务器连接成功
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MqttClient_Connected(object sender, EventArgs e)
        {           
            IsMqttConnected = true;
            Invoke((new Action(() =>
            {
                lbMqttSta.Text = "MQTT状态:已连接";
                lbMqttMsg.Text = ("已连接到MQTT服务器！" + Environment.NewLine);
            })));
        }

        /// <summary>
        /// 断开服务器连接
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MqttClient_Disconnected(object sender, EventArgs e)
        {
            IsMqttConnected = false;
            Invoke((new Action(() =>
            {
                lbMqttSta.Text = "MQTT状态:未连接";
                lbMqttMsg.Text = ("已断开MQTT连接！" + Environment.NewLine);
            })));
        }

        /// <summary>
        /// 接收到消息
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MqttClient_ApplicationMessageReceived(object sender, MqttApplicationMessageReceivedEventArgs e)
        {
            Invoke((new Action(() =>
            {
                lbMqttMsg.Text = ($">> {Encoding.UTF8.GetString(e.ApplicationMessage.Payload)}{Environment.NewLine}");
            })));
        }

        #endregion


        private void timer1_Tick(object sender, EventArgs e)
        {
            if (IsConnected)
            {
                lbTcpConnState.Text = "连接状态:已连接";
                tbTcpRevMsg.Text =  m_strStateMsg;
                  
            }
            else
            {
                lbTcpConnState.Text = "连接状态:未连接";
                if(sysParam.bMqttAutoConn &&  !IsTcpConnecting)
                {
                    ConnectToTcpServer();
                }
            } 

            if(IsMqttConnected)
            {
                lbMqttSta.Text = "Mqtt状态:已连接" ; 
                int mytime = iTimes * 1000;
                 
                if(sysParam.bMqttAutoSend)
                {
                    if (mytime % sysParam.iMqttInteval == 0)
                    {
                        SendCmd(sysParam.tcpCmd);
                        if (m_strStateMsg != "")
                            m_strMqttMsg = m_strStateMsg;
                        if (sysParam.bSimulateData) m_strMqttMsg = tbMqttContent.Text;
                        List<string> strMsg2 = m_strMqttMsg.Split(',').ToList();
                        while (strMsg2.Count < 10)
                        {
                            strMsg2.Add("");
                        }
                        SendMqttMsg2(strMsg2);
                    }
                } 
                iTimes++; 
            }
            else
            {
                lbMqttSta.Text = "Mqtt状态:未连接";
                if(sysParam.bMqttAutoConn && !IsMqttConnecting )
                {
                    Task.Run(async () => { await ConnectMqttServerAsync(); });
                }
            } 
        }

        private void SendMqttMsg(string strMsg)
        {
            string inputString = strMsg;
            var appMsg = new MqttApplicationMessage(sysParam.mqttPath, Encoding.UTF8.GetBytes(inputString), MqttQualityOfServiceLevel.AtMostOnce, false);
            mqttClient.PublishAsync(appMsg);
        }
        private void SendMqttMsg2(List<string> strMsg)
        {
            QyData qd = new QyData();
            qd.devname = sysParam.mqttDevName;
            qd.ic = strMsg[0]  ;
            qd.artno = strMsg[1];           // "artno001";
            qd.color =  strMsg[2];         //"黄色";
            qd.process =  strMsg[3];       // "工序01";
            qd.partsname =  strMsg[4];     //"弯管";
            qd.ordertype =  strMsg[5];     //"淘宝";
            qd.size = strMsg[6];           //"100";
            qd.count = strMsg[7];          //"360";
            qd.starttime = strMsg[8];      //"2022-01-19 16:47";
            qd.complatetime = strMsg[9];   //"2022-04-21 16:47";

            Jmeta jm = new Jmeta();
            //jm.t = 1552553109000;
            jm.t = DateUtil.ConvertDateTimeToLong(DateTime.Now);
            jm.expire = 3600;

            JowoData jwd = new JowoData();
            jwd.meta = jm;
            jwd.data = qd.toJdatas().ToArray();

            String strmag = JsonUtil.ToJson(jwd);
            SendMqttMsg(strmag);
        }

        private void btSendTcp_Click(object sender, EventArgs e)
        {
            string strmsg = tbStateMsg.Text;
            SendCmd(strmsg);
        }
       

        private void FrmServer_Load(object sender, EventArgs e)
        {
            m_bLoading = false;
        }
         
         
        private void lbTcpConnState_Click(object sender, EventArgs e)
        {

        }

        private void tbStateMsg_TextChanged(object sender, EventArgs e)
        {
            if (m_bLoading) return;
            sysParam.tcpCmd = tbStateMsg.Text;
        }
         

        private void lbUdpSta_Click(object sender, EventArgs e)
        {

        }

        private void btMqttConn_Click(object sender, EventArgs e)
        { 
            if (IsMqttConnected) return;
            if (IsMqttConnecting) return; 
            Task.Run(async () => { await ConnectMqttServerAsync(); });
        }

        private void btMqttSend_Click(object sender, EventArgs e)
        {
            if (IsMqttConnecting) return;
            if (!IsMqttConnected) return;

            m_strMqttMsg = tbMqttContent.Text;
            List<string> strMsg2 = m_strMqttMsg.Split(',').ToList();
            while(strMsg2.Count<10)
            {
                strMsg2.Add("");
            }  
            SendMqttMsg2(strMsg2);
        }

        private void cbMqttAutoConn_CheckedChanged(object sender, EventArgs e)
        {
            if (m_bLoading) return;
            sysParam.bMqttAutoConn = cbMqttAutoConn.Checked;
            sysParam.SaveParam();
        }

        private void cbAllowSim_CheckedChanged(object sender, EventArgs e)
        {
            if (m_bLoading) return;
            sysParam.bSimulateData = cbAllowSim.Checked;
            sysParam.SaveParam();
        }

        private void nudMqttInteval_ValueChanged(object sender, EventArgs e)
        {
            if (m_bLoading) return;
            sysParam.iMqttInteval = (int)nudMqttInteval.Value;
            sysParam.SaveParam();
        }

        private void tbMqttContent_TextChanged(object sender, EventArgs e)
        {
            if (m_bLoading) return;
            sysParam.mqttContent = tbMqttContent.Text;
            sysParam.SaveParam();
        }

        private void tbMqttTopic_TextChanged(object sender, EventArgs e)
        {
            if (m_bLoading) return;
            sysParam.mqttPath = tbMqttTopic.Text;
            sysParam.SaveParam();
        }

        private void tbMqttPwd_TextChanged(object sender, EventArgs e)
        {
            if (m_bLoading) return;
            sysParam.mqttPwd = tbMqttPwd.Text;
            sysParam.SaveParam();
        }

        private void tbMqttUsr_TextChanged(object sender, EventArgs e)
        {
            if (m_bLoading) return;
            sysParam.mqttUsr = tbMqttUsr.Text;
            sysParam.SaveParam();
        }

        private void tbMqttPort_TextChanged(object sender, EventArgs e)
        {
            if (m_bLoading) return;
            sysParam.mqttPort = int.Parse(tbMqttPort.Text);
            sysParam.SaveParam();
        }

        private void tbMqttIp_TextChanged(object sender, EventArgs e)
        {
            if (m_bLoading) return;
            sysParam.mqttIp = tbMqttIp.Text;
            sysParam.SaveParam();
        }

        private void devicename_TextChanged(object sender, EventArgs e)
        {
            if (m_bLoading) return;
            sysParam.mqttDevName = devicename.Text;
            sysParam.SaveParam();
        }

        private void cbMqttAutoSend_CheckedChanged(object sender, EventArgs e)
        {
            if (m_bLoading) return;
            sysParam.bMqttAutoSend = cbMqttAutoSend.Checked;
            sysParam.SaveParam();
        }

        private void btTcpConn_Click(object sender, EventArgs e)
        {
            ConnectToTcpServer();
        }

        private void FrmServer_FormClosing(object sender, FormClosingEventArgs e)
        {
            m_threadTcpRun = false;
        }

        private void tbLocalIP_TextChanged(object sender, EventArgs e)
        {
            if (m_bLoading) return;
            sysParam.tcpIP = tbLocalIP.Text;
            sysParam.SaveParam();
        }

        private void tbTcpPort_TextChanged(object sender, EventArgs e)
        {
            if (m_bLoading) return;
            sysParam.tcpPort = int.Parse(tbTcpPort.Text);
            sysParam.SaveParam();
        }

        private void cbAutoSendTcp_CheckedChanged(object sender, EventArgs e)
        {
            if (m_bLoading) return;
            sysParam.bTcpAutoSend = cbAutoSendTcp.Checked;
            sysParam.SaveParam();
        }
    }


}
